home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gscolor.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  10.6 KB  |  371 lines

  1. /* Copyright (C) 1989, 1992, 1993, 1994, 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gscolor.c,v 1.4 2000/09/19 19:00:26 lpd Exp $ */
  20. /* Color and halftone operators for Ghostscript library */
  21. #include "gx.h"
  22. #include "gserrors.h"
  23. #include "gsstruct.h"
  24. #include "gsutil.h"        /* for gs_next_ids */
  25. #include "gsccolor.h"
  26. #include "gscssub.h"
  27. #include "gxcspace.h"
  28. #include "gxdcconv.h"
  29. #include "gxdevice.h"        /* for gx_color_index */
  30. #include "gxcmap.h"
  31. #include "gzstate.h"
  32.  
  33. /* Imported from gsht.c */
  34. void gx_set_effective_transfer(P1(gs_state *));
  35.  
  36. /* Structure descriptors */
  37. public_st_client_color();
  38. public_st_transfer_map();
  39.  
  40. /* GC procedures */
  41. private 
  42. ENUM_PTRS_WITH(transfer_map_enum_ptrs, gx_transfer_map *mptr) return 0;
  43. case 0: ENUM_RETURN((mptr->proc == 0 ? mptr->closure.data : 0));
  44. ENUM_PTRS_END
  45. private RELOC_PTRS_WITH(transfer_map_reloc_ptrs, gx_transfer_map *mptr)
  46. {
  47.     if (mptr->proc == 0)
  48.     RELOC_PTR(gx_transfer_map, closure.data);
  49. }
  50. RELOC_PTRS_END
  51.  
  52. /* Initialize colors with 1, or 3, or 4 paint components. */
  53. /* (These are only used by setcolorspace.) */
  54. void
  55. gx_init_paint_1(gs_client_color * pcc, const gs_color_space * pcs)
  56. {
  57.     pcc->paint.values[0] = 0.0;
  58. }
  59. void
  60. gx_init_paint_3(gs_client_color * pcc, const gs_color_space * pcs)
  61. {
  62.     pcc->paint.values[2] = 0.0;
  63.     pcc->paint.values[1] = 0.0;
  64.     pcc->paint.values[0] = 0.0;
  65. }
  66. void
  67. gx_init_paint_4(gs_client_color * pcc, const gs_color_space * pcs)
  68. {
  69.     /* DeviceCMYK and CIEBasedDEFG spaces initialize to 0,0,0,1. */
  70.     pcc->paint.values[3] = 1.0;
  71.     gx_init_paint_3(pcc, pcs);
  72. }
  73.  
  74. /* Force a value into the range [0.0..1.0]. */
  75. #define FORCE_UNIT(p) (p <= 0.0 ? 0.0 : p >= 1.0 ? 1.0 : p)
  76.  
  77. /* Restrict colors with 1, 3, or 4 components to the range (0,1). */
  78. void
  79. gx_restrict01_paint_1(gs_client_color * pcc, const gs_color_space * pcs)
  80. {
  81.     pcc->paint.values[0] = FORCE_UNIT(pcc->paint.values[0]);
  82. }
  83. void
  84. gx_restrict01_paint_3(gs_client_color * pcc, const gs_color_space * pcs)
  85. {
  86.     pcc->paint.values[2] = FORCE_UNIT(pcc->paint.values[2]);
  87.     pcc->paint.values[1] = FORCE_UNIT(pcc->paint.values[1]);
  88.     pcc->paint.values[0] = FORCE_UNIT(pcc->paint.values[0]);
  89. }
  90. void
  91. gx_restrict01_paint_4(gs_client_color * pcc, const gs_color_space * pcs)
  92. {
  93.     pcc->paint.values[3] = FORCE_UNIT(pcc->paint.values[3]);
  94.     gx_restrict01_paint_3(pcc, pcs);
  95. }
  96.  
  97. /* Null reference count adjustment procedure. */
  98. void
  99. gx_no_adjust_color_count(const gs_client_color * pcc,
  100.              const gs_color_space * pcs, int delta)
  101. {
  102. }
  103.  
  104. /* Forward declarations */
  105. void load_transfer_map(P3(gs_state *, gx_transfer_map *, floatp));
  106.  
  107. /* setgray */
  108. int
  109. gs_setgray(gs_state * pgs, floatp gray)
  110. {
  111.     gs_client_color *pcc = pgs->ccolor;
  112.  
  113.     if (pgs->in_cachedevice)
  114.     return_error(gs_error_undefined);
  115.     cs_adjust_color_count(pgs, -1);
  116.     gs_cspace_assign(pgs->color_space, gs_current_DeviceGray_space(pgs));
  117.     pgs->orig_cspace_index = pgs->orig_base_cspace_index =
  118.     gs_color_space_index_DeviceGray;
  119.     pcc->paint.values[0] = FORCE_UNIT(gray);
  120.     pcc->pattern = 0;        /* for GC */
  121.     gx_unset_dev_color(pgs);
  122.     return 0;
  123. }
  124.  
  125. /* currentgray */
  126. int
  127. gs_currentgray(const gs_state * pgs, float *pg)
  128. {
  129.     const gs_client_color *pcc = pgs->ccolor;
  130.     const gs_imager_state *const pis = (const gs_imager_state *)pgs;
  131.  
  132.     switch (pgs->orig_cspace_index) {
  133.     case gs_color_space_index_DeviceGray:
  134.         *pg = pcc->paint.values[0];
  135.         break;
  136.     case gs_color_space_index_DeviceRGB:
  137.         *pg = frac2float(color_rgb_to_gray(
  138.                     float2frac(pcc->paint.values[0]),
  139.                     float2frac(pcc->paint.values[1]),
  140.                     float2frac(pcc->paint.values[2]),
  141.                     pis));
  142.         break;
  143.     case gs_color_space_index_DeviceCMYK:
  144.         *pg = frac2float(color_cmyk_to_gray(
  145.                     float2frac(pcc->paint.values[0]),
  146.                     float2frac(pcc->paint.values[1]),
  147.                     float2frac(pcc->paint.values[2]),
  148.                     float2frac(pcc->paint.values[3]),
  149.                     pis));
  150.         break;
  151.     default:
  152.         /*
  153.          * Might be another convertible color space, but this is rare,
  154.          * so we don't care about speed or (to some extent) accuracy.
  155.          */
  156.         {
  157.         float rgb[3];
  158.         int code = gs_currentrgbcolor(pgs, rgb);
  159.  
  160.         if (code < 0)
  161.             return code;
  162.         *pg = frac2float(color_rgb_to_gray(
  163.                            float2frac(rgb[0]),
  164.                            float2frac(rgb[1]),
  165.                            float2frac(rgb[2]),
  166.                            pis));
  167.         }
  168.     }
  169.     return 0;
  170. }
  171.  
  172. /* setrgbcolor */
  173. int
  174. gs_setrgbcolor(gs_state * pgs, floatp r, floatp g, floatp b)
  175. {
  176.     gs_client_color *pcc = pgs->ccolor;
  177.  
  178.     if (pgs->in_cachedevice)
  179.     return_error(gs_error_undefined);
  180.     cs_adjust_color_count(pgs, -1);
  181.     gs_cspace_assign(pgs->color_space, gs_current_DeviceRGB_space(pgs));
  182.     pgs->orig_cspace_index = pgs->orig_base_cspace_index =
  183.     gs_color_space_index_DeviceRGB;
  184.     pcc->paint.values[0] = FORCE_UNIT(r);
  185.     pcc->paint.values[1] = FORCE_UNIT(g);
  186.     pcc->paint.values[2] = FORCE_UNIT(b);
  187.     pcc->pattern = 0;        /* for GC */
  188.     gx_unset_dev_color(pgs);
  189.     return 0;
  190. }
  191.  
  192. /* currentrgbcolor */
  193. int
  194. gs_currentrgbcolor(const gs_state * pgs, float pr3[3])
  195. {
  196.     const gs_client_color *pcc = pgs->ccolor;
  197.     const gs_color_space *pcs = pgs->color_space;
  198.     const gs_color_space *pbcs = pcs;
  199.     const gs_imager_state *const pis = (const gs_imager_state *)pgs;
  200.     gs_color_space_index csi = pgs->orig_cspace_index;
  201.     frac fcc[4];
  202.     gs_client_color cc;
  203.     int code;
  204.  
  205.   sw:switch (csi) {
  206.     case gs_color_space_index_DeviceGray:
  207.         pr3[0] = pr3[1] = pr3[2] = pcc->paint.values[0];
  208.         return 0;
  209.     case gs_color_space_index_DeviceRGB:
  210.         pr3[0] = pcc->paint.values[0];
  211.         pr3[1] = pcc->paint.values[1];
  212.         pr3[2] = pcc->paint.values[2];
  213.         return 0;
  214.     case gs_color_space_index_DeviceCMYK:
  215.         color_cmyk_to_rgb(
  216.                  float2frac(pcc->paint.values[0]),
  217.                  float2frac(pcc->paint.values[1]),
  218.                  float2frac(pcc->paint.values[2]),
  219.                  float2frac(pcc->paint.values[3]),
  220.                  pis, fcc);
  221.         pr3[0] = frac2float(fcc[0]);
  222.         pr3[1] = frac2float(fcc[1]);
  223.         pr3[2] = frac2float(fcc[2]);
  224.         return 0;
  225.     case gs_color_space_index_DeviceN:
  226.     case gs_color_space_index_Separation:
  227.       ds:if (cs_concrete_space(pbcs, pis) == pbcs)
  228.         break;        /* not using alternative space */
  229.         /* (falls through) */
  230.     case gs_color_space_index_Indexed:
  231.         pbcs = gs_cspace_base_space(pbcs);
  232.         switch (pbcs->type->index) {
  233.         case gs_color_space_index_DeviceN:
  234.         case gs_color_space_index_Separation:
  235.             goto ds;
  236.         default:    /* outer switch will catch undefined cases */
  237.             break;
  238.         }
  239.         code = cs_concretize_color(pcc, pcs, fcc, pis);
  240.         if (code < 0)
  241.         return code;
  242.         cc.paint.values[0] = frac2float(fcc[0]);
  243.         cc.paint.values[1] = frac2float(fcc[1]);
  244.         cc.paint.values[2] = frac2float(fcc[2]);
  245.         cc.paint.values[3] = frac2float(fcc[3]);
  246.         pcc = &cc;
  247.         pcs = pbcs;
  248.         csi = pgs->orig_base_cspace_index;
  249.         goto sw;
  250.     default:
  251.         break;
  252.     }
  253.     pr3[0] = pr3[1] = pr3[2] = 0.0;
  254.     return 0;
  255. }
  256.  
  257. /* setnullcolor */
  258. int
  259. gs_setnullcolor(gs_state * pgs)
  260. {
  261.     if (pgs->in_cachedevice)
  262.     return_error(gs_error_undefined);
  263.     gs_setgray(pgs, 0.0);    /* set color space to something harmless */
  264.     color_set_null(pgs->dev_color);
  265.     return 0;
  266. }
  267.  
  268. /* settransfer */
  269. /* Remap=0 is used by the interpreter. */
  270. int
  271. gs_settransfer(gs_state * pgs, gs_mapping_proc tproc)
  272. {
  273.     return gs_settransfer_remap(pgs, tproc, true);
  274. }
  275. int
  276. gs_settransfer_remap(gs_state * pgs, gs_mapping_proc tproc, bool remap)
  277. {
  278.     gx_transfer_colored *ptran = &pgs->set_transfer.colored;
  279.  
  280.     /*
  281.      * We can safely decrement the reference counts
  282.      * of the non-gray transfer maps, because
  283.      * if any of them get freed, the rc_unshare can't fail.
  284.      */
  285.     rc_decrement(ptran->red, "gs_settransfer");
  286.     rc_decrement(ptran->green, "gs_settransfer");
  287.     rc_decrement(ptran->blue, "gs_settransfer");
  288.     rc_unshare_struct(ptran->gray, gx_transfer_map, &st_transfer_map,
  289.               pgs->memory, goto fail, "gs_settransfer");
  290.     ptran->gray->proc = tproc;
  291.     ptran->gray->id = gs_next_ids(1);
  292.     ptran->red = ptran->gray;
  293.     ptran->green = ptran->gray;
  294.     ptran->blue = ptran->gray;
  295.     ptran->gray->rc.ref_count += 3;
  296.     if (remap) {
  297.     load_transfer_map(pgs, ptran->gray, 0.0);
  298.     gx_set_effective_transfer(pgs);
  299.     gx_unset_dev_color(pgs);
  300.     }
  301.     return 0;
  302.   fail:
  303.     rc_increment(ptran->red);
  304.     rc_increment(ptran->green);
  305.     rc_increment(ptran->blue);
  306.     return_error(gs_error_VMerror);
  307. }
  308.  
  309. /* currenttransfer */
  310. gs_mapping_proc
  311. gs_currenttransfer(const gs_state * pgs)
  312. {
  313.     return pgs->set_transfer.colored.gray->proc;
  314. }
  315.  
  316. /* ------ Non-operator routines ------ */
  317.  
  318. /* Set device color = 1 for writing into the character cache. */
  319. void
  320. gx_set_device_color_1(gs_state * pgs)
  321. {
  322.     gx_device_color *pdc = pgs->dev_color;
  323.     gs_client_color *pcc = pgs->ccolor;
  324.  
  325.     cs_adjust_color_count(pgs, -1);
  326.     pcc->paint.values[0] = 0.0;
  327.     pcc->pattern = 0;        /* for GC */
  328.     color_set_pure(pdc, 1);
  329.     pgs->log_op = lop_default;
  330.     gs_cspace_assign(pgs->color_space,
  331.              gs_cspace_DeviceGray((const gs_imager_state *)pgs));
  332.     pgs->orig_cspace_index = pgs->orig_base_cspace_index =
  333.     gs_color_space_index_DeviceGray;
  334. }
  335.  
  336. /* ------ Internal routines ------ */
  337.  
  338. /*
  339.  * Load one cached transfer map.  We export this for gscolor1.c.
  340.  * Note that we must deal with both old (proc) and new (closure) maps.
  341.  */
  342. private float
  343. transfer_use_proc(floatp value, const gx_transfer_map * pmap,
  344.           const void *ignore_proc_data)
  345. {
  346.     return (*pmap->proc) (value, pmap);
  347. }
  348. void
  349. load_transfer_map(gs_state * pgs, gx_transfer_map * pmap, floatp min_value)
  350. {
  351.     gs_mapping_closure_proc_t proc;
  352.     const void *proc_data;
  353.     frac *values = pmap->values;
  354.     frac fmin = float2frac(min_value);
  355.     int i;
  356.  
  357.     if (pmap->proc == 0)    /* use closure */
  358.     proc = pmap->closure.proc, proc_data = pmap->closure.data;
  359.     else            /* use proc */
  360.     proc = transfer_use_proc, proc_data = 0 /* not used */;
  361.     for (i = 0; i < transfer_map_size; i++) {
  362.     float fval =
  363.     (*proc) ((float)i / (transfer_map_size - 1), pmap, proc_data);
  364.  
  365.     values[i] =
  366.         (fval < min_value ? fmin :
  367.          fval >= 1.0 ? frac_1 :
  368.          float2frac(fval));
  369.     }
  370. }
  371.